package com.ktjiaoyu.server.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ktjiaoyu.server.mapper.AdminRoleMapper;
import com.ktjiaoyu.server.mapper.MenuMapper;
import com.ktjiaoyu.server.mapper.MenuRoleMapper;
import com.ktjiaoyu.server.mapper.RoleMapper;
import com.ktjiaoyu.server.pojo.*;
import com.ktjiaoyu.server.service.IAdminRoleService;
import com.ktjiaoyu.server.service.IAdminService;
import com.ktjiaoyu.server.service.IMenuRoleService;
import com.ktjiaoyu.server.service.IRoleService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 角色模块业务接口实现类
 * @author jieGe
 * @since 2022/2/13 - 2:20
 */
@Service("roleService")
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements IRoleService {

    @Resource
    private RoleMapper roleMapper;

    // 查询所有的角色列表信息
    @Override
    public List<Role> roleList() {
        return roleMapper.selectList(null);
    }

    @Resource
    private IAdminRoleService adminRoleService;

    @Resource
    private IAdminService adminService;

    @Resource
    private MenuRoleMapper menuRoleMapper;

    @Resource
    private MenuMapper menuMapper;

    @Resource
    private AdminRoleMapper adminRoleMapper;

    @Resource
    private IMenuRoleService menuRoleService;

    // 为用户分配多个角色时，需要往t_admin_role表中插入数据
    @Override
    public boolean batchInsertAdminRole(AdminRoleVo vo) {
        // 1、获取从前端传递过来的角色ID集合(转换成List泛型集合)
        List<Integer> updatedRids = Arrays.asList(vo.getRid());
        // 2、获取当前用户自身原有的角色ID集合(只需要得到角色ID即可)
        List<Integer> existRids = adminService.findRolesByAdminId(vo.getAdminId()).stream().map((role) ->{
            return role.getId();
        }).collect(Collectors.toList());
        /**
         * 获取需要【删除】的rids,即用户自身存在角色ID集合，而前端传递过来的角色ID集合里面是没有的
         * existRids - updatedRids  自身有的角色ID集合(大) - 前端传递的角色ID集合(小)
         */
        // 使用jdk1.8新特性中的fileter过滤出想要的数据
        // 遍历当前用户自身拥有的角色ID集合
        List<Integer> delRids = existRids.stream().filter((rid) -> {
// 过滤条件是前端传递过来的角色ID集合中不包含当前迭代的角色ID
            return !updatedRids.contains(rid);
        }).collect(Collectors.toList());

        /**
         * 获取需要【新增】的rids,前端传递过来的角色ID集合里面是有的，而当前用户自身没有拥有这个角色ID
         *  updatedRids - existRids 前端传递过来的角色ID集合(大) - 自身拥有的角色ID(小)
         */
        List<Integer> saveRids = updatedRids.stream().filter((uRid) -> {
            return !existRids.contains(uRid);
        }).collect(Collectors.toList());
        try {
            // 往t_admin_role用户角色中间表中增量删除数据
            if (delRids.size() > 0) for (Integer rid : delRids) {
                adminRoleService.remove(new QueryWrapper<AdminRole>().
                        eq("rid", rid).
                        eq("adminId", vo.getAdminId()));
            }
            // 往t_admin_role用户角色中间表中增量新增数据
            if (saveRids.size() > 0) {
                // 遍历需要进行新增的角色ID集合
                List<AdminRole> saveAdminRole = saveRids.stream().map((rid) -> {
                    return new AdminRole(vo.getAdminId(), rid); //注：需要到AdminRole实体类中添加构造方法
                }).collect(Collectors.toList());
                // 调用saveBatch方法往t_admin_role用户角色中间表中增量新增数据
                adminRoleService.saveBatch(saveAdminRole);
            }
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    // 通过操作员ID查询其拥有的角色列表权限
    @Override
    public AdminRoleVo getAdminRoleList(Integer adminId) {
        QueryWrapper<AdminRole> wrapper = new QueryWrapper<AdminRole>();
        wrapper.eq("adminId", adminId);
        List<AdminRole> arList = adminRoleMapper.selectList(wrapper);
        // 如果当前用户没有被分配一个角色权限，那么就返回空的AdminRoleVo对象
        if (arList == null || arList.size() == 0) {
            return new AdminRoleVo();
        }
        List<Integer> ids = new ArrayList<Integer>();
        for (AdminRole ar : arList) {
            ids.add(ar.getRid());
        }
        AdminRoleVo vo = new AdminRoleVo(adminId, ids.toArray(new Integer[ids.size()]));
        return vo;
    }

    // 分页显示角色列表, 角色英文名称或角色中文名称模糊查询
    @Override
    public IPage<Role> selectByPage(Page<Role> page, String query, String sort) {
        QueryWrapper<Role> queryWrapper = new QueryWrapper<Role>();
        if (StringUtils.isNotEmpty(query)) {
            // 如果查询条件query，不为空，那么就按角色英文名称或角色中文名称模糊查询
            queryWrapper.like("name", query).or().like("nameZh", query);
        }

        // 按id字段进行升序或降序排(取决限前端点击id所在列头)
        if (sort.equals("+id")) {
            queryWrapper.orderByAsc("id");
        } else {
            queryWrapper.orderByDesc("id");
        }
        IPage<Role> pageList = roleMapper.selectPage(page, queryWrapper);
        // 获取到角色列表
        List<Role> roleList = pageList.getRecords();
        // 遍历所有的角色列表信息
        roleList = roleList.stream().map((role) -> {
            // 遍历所有的角色列表，查询每个角色下的权限列表(这个权限列表需要进行一级、二级、三级分类)
            role.setChildren(getRightListByRole(role));
            return role;
        }).collect(Collectors.toList());
        return pageList;
    }

    // 查询当前角色所授权的所有权限
    private List<Menu> getRightListByRole(Role role) {
        // 查询当前角色下的权限列表集合
        List<Menu> menuList = roleMapper.findMenuByRole(role.getId());
        List<Menu> menus = null;
        if (menuList != null && menuList.size() > 0) {
            menus = menuList.stream().filter((menu) -> {
                // 过滤出当前角色下的一级权限列表，之后再调用map对这个一级权限列表进行遍历
                return menu.getParentId() != null && menu.getParentId() == 1;
            }).map((oneLevelMenu) -> { // 调用map对这个一级权限列表进行遍历
                // 遍历一级权限得到一级权限下的二级权限。
                oneLevelMenu.setChildren(getChildrens(oneLevelMenu, menuList));
                return oneLevelMenu;
            }).collect(Collectors.toList());
        } else {
            return null;
        }
        return menus;
    }

    /**
     * 得到当前权限下的子权限集合
     * @param oneLevelMenu 权限对象(比如一级或二级)
     * @param menuList 为当前角色所拥有的所有权限集合
     * @return 返回当前权限下的子权限列表
     */
    private List<Menu> getChildrens(Menu oneLevelMenu, List<Menu> menuList) {
        List<Menu> childMenuList = menuList.stream().filter((menu) ->
                // 过滤条件是：权限集合中menu对象的pid父级ID == 当前权限对象oneLevelMenu的ID
                // 实现将当前权限对象oneLevelMenu的子权限列表过滤出来，如果onLevelMenu为一级权限，
                // 那么就可以把这个一级权限下的二级权限给过滤出来。
                menu.getParentId() == oneLevelMenu.getId()
        ).map((sonMenu) -> {
            // 调用map方法，将过滤出来的子权限查询进行遍历。
            sonMenu.setChildren(getChildrens(sonMenu, menuList));
            return sonMenu;
        }).collect(Collectors.toList());
        return childMenuList;
    }

    // 根据角色ID删除对应的权限,将当前角色最新的权限列表进行返回
    @Override
    public List<Menu> delMenuByRoleId(Integer roleId, Integer menuId) {
        // 查询menu权限对象的所有子权限，并将这些子权限的id追加到List集合中
        List<Integer> sonMenuIds = getSonMenuIds(roleId, menuId);
        Integer[] menuIds = null; //多个子权限id使用逗号进行拼接
        if (sonMenuIds != null && sonMenuIds.size() > 0) {
            // 将List<Integer>转换成Integer[]数组
            menuIds = sonMenuIds.toArray(new Integer[sonMenuIds.size()]);
        }

        // 1、根据角色ID删除对应的权限(从t_menu_role表)
        QueryWrapper<MenuRole> wrapper = new QueryWrapper<MenuRole>();
        wrapper.eq("rid", roleId);
        if (menuIds == null || menuIds.length == 0) {
            // 说明本次删除是删除角色下的三级权限
            wrapper.eq("mid", menuId);
        } else {
            // 说明本次删除是删除角色下的一级或二级权限
            // DELETE FROM `t_menu_role` WHERE rid = 1 AND `mid` IN (10, 46)
            wrapper.in("mid", menuIds);
        }

        // delete from t_menu_role where mid = ? and rid = ?
        menuRoleMapper.delete(wrapper);
        // 2、将当前角色最新的权限列表查询出来，再进行返回
        Role role = new Role();
        role.setId(roleId);
        List<Menu> menus = getRightListByRole(role);
        return menus;
    }

    // 保存角色信息
    @Override
    public boolean saveRole(Role role) {
        return roleMapper.insert(role)>0?true:false;
    }

    @Override
    public boolean updateRole(Role role) {
        return roleMapper.updateById(role)>0 ? true:false;
    }

    // 为角色分配多个菜单权限
    @Override
    public boolean batchInsertRoleMenu(RoleMenuVo vo) {
        //1、获取从前端传递过来的权限ID集合(修改后的)
        List<Integer> updatedMid = Arrays.asList(vo.getMid());
        //2、获取当前角色自身原有的权限ID集合(只需要得到权限ID即可)
        //2.1 通过角色ID查询t_menu_role菜单角色中间的相关数据
        List<MenuRole> mRList = menuRoleMapper.selectList(new QueryWrapper<MenuRole>().eq("rid", vo.getRid()));
        //2.2 再从菜单角色对象集合中取出所有的菜单权限ID(即得到当前角色本身所拥有的菜单权限ID集合)
        List<Integer> existMids = mRList.stream().map((mr) -> {
            return mr.getMid();
        }).collect(Collectors.toList());

        /**
         * 获取需要【删除】的菜单ID集合,即角色自身存在菜单ID集合，而前端传递过来的菜单ID集合里面是没有的
         * existMids - updatedMid  自身有的菜单ID集合(大) - 前端传递的菜单ID集合(小)
         */
        List<Integer> delMids = existMids.stream().filter((mid) -> {
            return !updatedMid.contains(mid);
        }).collect(Collectors.toList());

        /**
         * 获取需要【新增】的菜单ID集合,前端传递过来的菜单ID集合里面是有的，而当前用户自身没有拥有这个菜单ID
         *  updatedMid - existMids 前端传递过来的菜单ID集合(大) - 自身拥有的菜单ID(小)
         */
        List<Integer> saveMids = updatedMid.stream().filter((mid) -> {
            return !existMids.contains(mid);
        }).collect(Collectors.toList());

        try {
            // 往t_menu_role菜单角色中间表中增量删除数据
            if (delMids.size() > 0) for (Integer mid : delMids) {
                menuRoleService.remove(new QueryWrapper<MenuRole>().
                        eq("rid", vo.getRid()).
                        eq("mid", mid));
            }
            // 往t_menu_role菜单角色中间表中增量新增数据
            if (saveMids.size() > 0) {
                // 遍历需要进行新增的菜单权限ID集合
                List<MenuRole> saveMenuRole = saveMids.stream().map((mid) -> {
                    return new MenuRole(vo.getRid(), mid); //注：需要到MenuRole实体类中添加构造方法
                }).collect(Collectors.toList());
                // 调用saveBatch方法往t_menu_role用户角色中间表中增量新增数据
                menuRoleService.saveBatch(saveMenuRole);
            }
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    // 通过角色ID删除角色信息
    @Override
    public boolean delRoleById(Integer roleId) {
        try {
            // 1、通过角色ID到t_admin_role用户与角色中间表中删除相关信息
            adminRoleMapper.delete(new QueryWrapper<AdminRole>().eq("rid", roleId));
            // 2、通过角色ID到t_menu_role权限与角色中间表中删除相关信息
            menuRoleMapper.delete(new QueryWrapper<MenuRole>().eq("rid", roleId));
            // 3、再通过角色ID到t_role角色表中删除此角色信息
            roleMapper.deleteById(roleId);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    // 查询menu权限对象的所有子权限，并将这些子权限的id追加到List集合中
    private List<Integer> getSonMenuIds(Integer roleId, Integer menuId) {
        List<Integer> menuIds = new ArrayList<Integer>();
        // 通过即将要删除的权限id查询其详情对象信息
        Menu delMenu = menuMapper.selectById(menuId);
        if (3 != delMenu.getMenuLevel()) {
            // 判断要删除的菜单的等级是否为3，即三级权限，如果不是三级权限，那么在删除比如二级权限时，后面还需要将二级权限下的子权限一起从t_menu_role表中删除
            Role role = new Role();
            role.setId(roleId);
            // 获取当前角色下的所有权限
            List<Menu> menus = getRightListByRole(role);
            // 判断即将要删除的权限其权限等级是1还是2
            if (delMenu.getMenuLevel() == 1) {
                // 一级权限
                for (Menu currMenu : menus) {
                    if (currMenu.getId() == delMenu.getId()) {
                        menuIds.add(currMenu.getId());
                        // 遍历一级下的二级权限
                        for (Menu sonMenu : currMenu.getChildren()) {
                            menuIds.add(sonMenu.getId());
                            // 遍历二级下的三级权限
                            for (Menu threeMenu : sonMenu.getChildren()) {
                                menuIds.add(threeMenu.getId());
                            }
                        }
                        return menuIds;
                    }
                }
            } else {
                // 二级权限
                for (Menu currMenu : menus) {
                    // 遍历二级权限
                    for (Menu twoMenu : currMenu.getChildren()) {
                        if (twoMenu.getId() == delMenu.getId()) {
                            menuIds.add(twoMenu.getId());
                            // 遍历二级下的三级权限
                            for (Menu threeMenu : twoMenu.getChildren()) {
                                menuIds.add(threeMenu.getId());
                            }
                            return menuIds;
                        }
                    }
                }
            }
            return null;
        } else {
            return null;
        }
    }
}
